package net.kleinhenz.norabase.client.datasource;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.fields.DataSourceDateField;
import com.smartgwt.client.data.fields.DataSourceIntegerField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.rpc.RPCResponse;
import com.smartgwt.client.widgets.grid.ListGridRecord;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.kleinhenz.norabase.shared.SortOrientation;
import net.kleinhenz.norabase.shared.TextMatchStyle;
import net.kleinhenz.norabase.shared.model.Comment;
import net.kleinhenz.norabase.shared.model.BattlegroupComment;
import net.kleinhenz.norabase.shared.model.RuneComment;

public class CommentDS extends GwtRpcDataSource {

	private String battlegroupId = null;
	private Integer runeId = null;
	private String runeType = null;
	
    public CommentDS(String battlegroupId) {
    	super();
    	this.battlegroupId = battlegroupId;
    	configureColumns();
    }

    public CommentDS(Integer runeId, String runeType) {
    	super();
    	this.runeId = runeId;
    	this.runeType = runeType;
    	configureColumns();
    }

    public String getBattlegroupId() {
    	return this.battlegroupId;
    }
    
    public String getRuneType() {
    	return this.runeType;
    }
    
    public Integer getRuneId() {
    	return this.runeId;
    }

    public boolean isRuneCommentDS() {
    	return (battlegroupId==null);
    }

    public boolean isBattlegroupCommentDS() {
    	return !isRuneCommentDS();
    }

    private void configureColumns() {

    	DataSourceField field;
        field = new DataSourceIntegerField ("id", "Id");
        field.setPrimaryKey (true);
        field.setRequired(false);
        field.setCanEdit(false);
        field.setHidden(true);
        addField(field);

        field = new DataSourceTextField ("commentHTML", "Comment HTML");
        field.setRequired(true);
        field.setCanEdit(false);
        field.setHidden(false);
        addField(field);

        field = new DataSourceTextField ("accountId", "Account");
        field.setRequired(true);
        field.setCanEdit(false);
        field.setHidden(true);
        addField(field);

        field = new DataSourceTextField ("comment", "Comment");
        field.setRequired(true);
        field.setCanEdit(false);
        field.setHidden(true);
        addField(field);

        field = new DataSourceIntegerField ("rating", "Rating");
        field.setRequired(true);
        field.setCanEdit(false);
        field.setHidden(true);
        addField(field);

        field = new DataSourceDateField("date", "Date");
        field.setRequired(true);
        field.setCanEdit(false);
        field.setHidden(true);
        addField(field);

    	if (isRuneCommentDS()) {
    		field = new DataSourceTextField ("runeId", "Rune Id");
            field.setRequired(true);
            field.setCanEdit(false);
            field.setHidden(true);
            addField(field);

            field = new DataSourceTextField ("type", "Rune Type");
            field.setRequired(true);
            field.setCanEdit(false);
            field.setHidden(true);
            addField(field);
    	} else if (isBattlegroupCommentDS()) {
            field = new DataSourceTextField ("battlegroupId", "Battlegroup Id");
            field.setRequired(true);
            field.setCanEdit(false);
            field.setHidden(true);
            addField(field);
    	}
    }
    
    @SuppressWarnings("unchecked")
	@Override
    protected void executeFetch (final String requestId, final DSRequest request, final DSResponse response) {

    	if (getBattlegroupId()==null && getRuneId()==null) {
    		
    		response.setData(new ListGridRecord[0]);
    		response.setTotalRows(0);
    		processResponse(requestId, response);
    	} else {
	    	
	    	// aquiring meta data
	    	final Map<String, SortOrientation> sortSpec = convertSortSpecifier(request.getSortBy());
	        final int startIndex = (request.getStartRow() < 0)?0:request.getStartRow();
	        final int endIndex = (request.getEndRow() == null)?-1:request.getEndRow();
	        final TextMatchStyle textMatchStyle = convertTextMatchStyle(request.getTextMatchStyle());
	        final Map<String, Object> criteria = request.getCriteria().getValues();
	        
	        // server connection
	        CommentDSServiceAsync service = GWT.create(CommentDSService.class);
	        service.fetch(startIndex, endIndex, sortSpec, textMatchStyle, criteria, getBattlegroupId(), getRuneId(), getRuneType(),
	        		new AsyncCallback<List<Comment>>() {
	            public void onFailure(Throwable caught) {
	                response.setStatus(RPCResponse.STATUS_FAILURE);
	                processResponse(requestId, response);
	            }
	            public void onSuccess(List<Comment> result) {
	                ListGridRecord[] list = new ListGridRecord[result.size()];
	                if (result.size() > 0) {
	                    for (int i = 0; i < result.size(); i++) {
	                        ListGridRecord record = new ListGridRecord ();
	                        copyValues(result.get(i), record);
	                        list[i] = record;
	                    }
	                }
	                response.setData(list);
	                // IMPORTANT: for paging to work we have to specify size of full result set
	                response.setTotalRows(result.size());
	                processResponse(requestId, response);
	            }
	        });
    	}
    }

    @Override
    protected void executeAdd (final String requestId, final DSRequest request, final DSResponse response) {
        JavaScriptObject data = request.getData();
        ListGridRecord rec = new ListGridRecord(data);
        Comment comment = isRuneCommentDS() ? new RuneComment() : new BattlegroupComment();
        copyValues(rec, comment);
        CommentDSServiceAsync service = GWT.create(CommentDSService.class);
        service.add(comment, new AsyncCallback<Comment>() {
            public void onFailure (Throwable caught) {
                response.setStatus (RPCResponse.STATUS_FAILURE);
                processResponse (requestId, response);
            }
            public void onSuccess (Comment result) {
                ListGridRecord[] list = new ListGridRecord[1];
                ListGridRecord newRec = new ListGridRecord();
                copyValues(result, newRec);
                list[0] = newRec;
                response.setData(list);
                processResponse(requestId, response);
            }
        });
    }

    @Override
    protected void executeRemove(final String requestId, final DSRequest request, final DSResponse response) {
        JavaScriptObject data = request.getData();
        final ListGridRecord rec = new ListGridRecord(data);
        Comment comment = isRuneCommentDS() ? new RuneComment() : new BattlegroupComment();
        copyValues(rec, comment);
        CommentDSServiceAsync service = GWT.create(CommentDSService.class);
        service.remove(comment, new AsyncCallback<Comment> () {
            public void onFailure(Throwable caught) {
                response.setStatus(RPCResponse.STATUS_FAILURE);
                processResponse(requestId, response);
            }
            public void onSuccess(Comment result) {
                ListGridRecord[] list = new ListGridRecord[1];
                // We do not receive removed record from server.
                // Return record from request.
                list[0] = rec;
                response.setData(list);
                processResponse(requestId, response);
            }

        });
    }
    
    public static void copyValues(ListGridRecord from, Comment to) {

    	to.setId(from.getAttributeAsString("id"));
    	to.setAccountId(from.getAttributeAsString("accountId"));
    	to.setComment(from.getAttributeAsString("comment"));
    	to.setRating(from.getAttributeAsInt("rating"));
    	to.setDate(from.getAttributeAsDate("date"));

    	if (to instanceof RuneComment) {
        	((RuneComment)to).setRuneId(from.getAttributeAsInt("runeId"));
        	((RuneComment)to).setType(from.getAttributeAsString("type"));
    	} else if (to instanceof BattlegroupComment) {
        	((BattlegroupComment)to).setBattlegroupId(from.getAttributeAsString("battlegroupId"));
    	}
    }

	public static void copyValues(Comment from, ListGridRecord to) {

		to.setAttribute("id", from.getId());
		to.setAttribute("accountId", from.getAccountId());
		to.setAttribute("comment", from.getComment());
		to.setAttribute("rating", from.getRating());
		to.setAttribute("date", from.getDate());

    	if (from instanceof RuneComment) {
    		to.setAttribute("runeId", ((RuneComment)from).getRuneId());
    		to.setAttribute("type", ((RuneComment)from).getType());
    	} else if (from instanceof BattlegroupComment) {
    		to.setAttribute("battlegroupId", ((BattlegroupComment)from).getBattlegroupId());
    	}
    	
    	to.setAttribute("commentHTML", createHTML(from));
	}

	protected static String createHTML(Comment comment) {

		StringBuffer buf = new StringBuffer();
		buf.append("<p>");
		buf.append("<span style='color: #000000'>");
		for (int i=0;i<comment.getRating();i++)
			buf.append("&diams;");
		buf.append("</span>");
		buf.append("<span style='color: #bbbbbb'>");
		for (int i=0;i<5-comment.getRating();i++)
			buf.append("&diams;");
		buf.append("</span>");
		buf.append(" <b>");
		buf.append(comment.getAccountId());
		buf.append("</b> on ");
		buf.append(DateTimeFormat.getMediumDateTimeFormat().format(comment.getDate()));
		buf.append("<br>");
		buf.append(comment.getComment());
		buf.append("</p>");
		return buf.toString();
	}	

	protected Map<String, SortOrientation> convertSortSpecifier(com.smartgwt.client.data.SortSpecifier[] sortSpecifiers) {

		Map<String, SortOrientation> sp = new HashMap<String, SortOrientation>();
		if (sortSpecifiers!=null)
			for (com.smartgwt.client.data.SortSpecifier sortSpecifier : sortSpecifiers) {
				sp.put(sortSpecifier.getField(), 
						SortOrientation.ASCENDING.equals(sortSpecifier.getSortDirection()) ? SortOrientation.ASCENDING : SortOrientation.DESCENDING);
			}
		return sp;
	}

	protected TextMatchStyle convertTextMatchStyle(com.smartgwt.client.types.TextMatchStyle textMatchStyle) {

    	if (com.smartgwt.client.types.TextMatchStyle.EXACT.equals(textMatchStyle))
    		return TextMatchStyle.EXACT;
    	else if (com.smartgwt.client.types.TextMatchStyle.STARTS_WITH.equals(textMatchStyle))
    		return TextMatchStyle.STARTS_WITH;
    	else if (com.smartgwt.client.types.TextMatchStyle.SUBSTRING.equals(textMatchStyle))
    		return TextMatchStyle.SUBSTRING;
    	else
    		throw new RuntimeException("Unknown TextMatchStyle " + textMatchStyle.toString());
    }

	@Override
	protected void executeUpdate(String requestId, DSRequest request,
			DSResponse response) {
		throw new RuntimeException("Not implemented.");
	}
}
